package com.gateplugins;

import gate.AnnotationSet;
import gate.Factory;
import gate.Resource;
import gate.creole.AbstractLanguageAnalyser;
import gate.creole.ExecutionException;
import gate.creole.ResourceInstantiationException;
import gate.creole.metadata.CreoleParameter;
import gate.creole.metadata.CreoleResource;
import gate.creole.metadata.Optional;
import gate.creole.metadata.RunTime;
import gate.util.InvalidOffsetException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import com.twitter.Extractor;

@CreoleResource(name = "Twitter Tag Creator PR", comment = "Creates twitter specific markup: url, hashtag, mention, cashtag. "
		+ "Based on official twitter regular expressions.")
public class TwitterTagCreator extends AbstractLanguageAnalyser {
	private static final long serialVersionUID = 1L;

	String modelFilePath;
	String outputAS;
	String inputAS;
	private Extractor extractor;

	@Override
	public Resource init() throws ResourceInstantiationException {
		extractor = new Extractor();
		return this;
	}

	@Override
	public void execute() throws ExecutionException {
		String text = document.getContent().toString();
		List<Extractor.Entity> entities = new ArrayList<Extractor.Entity>();
		entities.addAll(extractor.extractEntitiesWithIndices(text));

		removeOverlappingEntities(entities);

		AnnotationSet outAS = null;
		if (outputAS != null) {
			outAS = document.getAnnotations(outputAS);
		} else {
			outAS = document.getAnnotations();
		}
		try {
			for (Extractor.Entity entity : entities) {
				outAS.add((long) entity.getStart(), (long) entity.getEnd(), entity.getType().toString().toLowerCase(),
						Factory.newFeatureMap());
			}
		} catch (InvalidOffsetException e) {
			e.printStackTrace();
			throw new ExecutionException(e);
		}
	}

	private void removeOverlappingEntities(List<Extractor.Entity> entities) {
		// sort by index

		Collections.sort(entities, new Comparator<Extractor.Entity>() {
			public int compare(Extractor.Entity e1, Extractor.Entity e2) {
				return e1.getStart() - e2.getStart();
			}
		});

		// Remove overlapping entities.
		// Two entities overlap only when one is URL and the other is hashtag/mention
		// which is a part of the URL. When it happens, we choose URL over hashtag/mention
		// by selecting the one with smaller start index.
		if (!entities.isEmpty()) {
			Iterator<Extractor.Entity> it = entities.iterator();
			Extractor.Entity prev = it.next();
			while (it.hasNext()) {
				Extractor.Entity cur = it.next();
				if (prev.getEnd() > cur.getStart()) {
					it.remove();
				} else {
					prev = cur;
				}
			}
		}
	}

	@Optional
	@RunTime
	@CreoleParameter(comment = "name of the annotationSet used for output")
	public void setOutputAnnotationSetName(String setName) {
		this.outputAS = setName;
	}
	
	@Override
	public void reInit() throws ResourceInstantiationException {
		init();
	}

	public String getOutputAnnotationSetName() {
		return outputAS;
	}
}
